using System;
using System.Collections.Generic;
using System.Text;
using NBusiness.CodeDom.Compiler;
using Microsoft.VisualStudio.Package;
using NBusiness.CodeDom;
using NBusiness.ESharp;
using NBusiness.ESharp.Compiler;
using System.Reflection;
using NBusiness.Data;
using NBusiness.Templates;
using NBusiness.Utilities;
using System.ComponentModel;

namespace NBusiness.VisualStudio.Language
{
    internal class ESharpDeclaration : IComparable<ESharpDeclaration>
    {
        public ESharpDeclaration(string title, string shortcut, string description, EntityElementType type)
        {
            _title = title;
            _shortcut = shortcut;
            _description = description;
            _type = type;
        }

        private string _title;
        private string _shortcut;
        private string _description;
        private EntityElementType _type;

        public string Title
        {
            get { return _title; }
        }
        public string Shortcut
        {
            get { return _shortcut; }
        }
        public string Description
        {
            get { return _description; }
        }
        public EntityElementType Type
        {
            get { return _type; }
        }

        internal static ESharpDeclaration[] GetDeclarations(EntityRoot root, EntityElement element, ParseReason reason)
        {
            EntityCompileUnit unit = root.GetUnitByElement(element);

            List<ESharpDeclaration> declarations = new List<ESharpDeclaration>();
            switch (reason)
            {
                case ParseReason.DisplayMemberList:
                    {
                        switch (element.Type)
                        {
                            case EntityElementType.AccessAllow:
                            case EntityElementType.AuthorizeAllow:
                                declarations.Add(new ESharpDeclaration("allow", "", "Allow a role to access this entity", element.Type));
                                declarations.Add(new ESharpDeclaration("deny", "", "Deny a role from accessing thie entity", element.Type));
                                break;
                            case EntityElementType.AuthorizeType:
                                declarations.Add(new ESharpDeclaration("fetch", "", "", element.Type));
                                declarations.Add(new ESharpDeclaration("insert", "", "", element.Type));
                                declarations.Add(new ESharpDeclaration("update", "", "", element.Type));
                                declarations.Add(new ESharpDeclaration("delete", "", "", element.Type));
                                break;
                            case EntityElementType.AccessType:
                                declarations.Add(new ESharpDeclaration("get", "", "", element.Type));
                                declarations.Add(new ESharpDeclaration("set", "", "", element.Type));
                                break;
                            case EntityElementType.ActionWhenType:
                                foreach(string eat in Enum.GetNames(typeof(EntityActionType)))
                                {
                                    declarations.Add(new ESharpDeclaration(eat.ToLower(), "", "", element.Type));
                                }
                                break;
                            case EntityElementType.FieldAutoProperty:
                            case EntityElementType.FieldType:
                                foreach (string name in ESharpParser.GetFieldTypeNames())
                                {
                                    declarations.Add(new ESharpDeclaration(name, "", "", element.Type));
                                }
                                break;
                            case EntityElementType.RelationshipField:
                            case EntityElementType.AccessField:
                                if (unit != null && unit is IHasParent)
                                {
                                    foreach (EntityField f in ((unit as IHasParent).Parent as Entity).Fields)
                                    {
                                        declarations.Add(new ESharpDeclaration(f.Name, "", "", element.Type));
                                    }
                                }
                                break;
                            case EntityElementType.ValidateProperty:
                                if (unit != null && unit is IHasParent)
                                {
                                    foreach (EntityField f in ((unit as IHasParent).Parent as Entity).Fields)
                                    {
                                        declarations.Add(new ESharpDeclaration(f.Name, "", "", element.Type));
                                    }
                                    foreach (EntityRelationship r in ((unit as IHasParent).Parent as Entity).Relationships)
                                    {
                                        if (r.From == ((unit as IHasParent).Parent as Entity))
                                        {
                                            declarations.Add(new ESharpDeclaration(r.Name, "", "", element.Type));
                                        }
                                    }
                                }
                                break;
                            case EntityElementType.ValidateType:
                                {
                                    if (root.Using.ContainsKey(element.Path))
                                    {
                                        Type t = typeof(ValidationRule);
                                        Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
                                        EntityUsing[] namespaces = root.Using[element.Path].ToArray();

                                        foreach (Type type in Reflection.FindTypes(t, assemblies, namespaces))
                                        {
                                            string description = string.Empty;
                                            if (type.IsDefined(typeof(DescriptionAttribute), false))
                                            {
                                                description = (type.GetCustomAttributes(typeof(DescriptionAttribute), false)[0] as DescriptionAttribute).Description;
                                            }
                                            declarations.Add(new ESharpDeclaration(type.Name.Replace("Rule", "").ToLower(), "", description, element.Type));
                                        }
                                    }
                                    break;
                                }
                            case EntityElementType.EntityTemplate:
                                if (root.Using.ContainsKey(element.Path))
                                {
                                    Type t = typeof(ITemplate);
                                    Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
                                    EntityUsing[] namespaces = root.Using[element.Path].ToArray();

                                    foreach (Type type in Reflection.FindTypes(t, assemblies, namespaces))
                                    {
                                        bool valid = true;
                                        foreach (EntityTemplate template in (unit as Entity).As)
                                        {
                                            if (template.Type == type.FullName)
                                            {
                                                valid = false;
                                                break;
                                            }
                                        }

                                        if (valid)
                                        {
                                            string description = string.Empty;
                                            if (type.IsDefined(typeof(DescriptionAttribute), false))
                                            {
                                                description = (type.GetCustomAttributes(typeof(DescriptionAttribute), false)[0] as DescriptionAttribute).Description;
                                            }
                                            declarations.Add(new ESharpDeclaration(type.Name.Replace("Template", ""), "", description, element.Type));
                                        }
                                    }
                                }
                                break;
                            case EntityElementType.RelationshipWith:
                            case EntityElementType.RelationshipEntity:
                                foreach (Entity e in ((unit as EntityRelationship).Parent.Parent as EntityFamily).Entities)
                                {
                                    if(e.Name != ((unit as EntityRelationship).Parent as Entity).Name)
                                        declarations.Add(new ESharpDeclaration(e.Name, "", "", element.Type));
                                }
                                break;
                            case EntityElementType.RelationshipAssignTo:
                                foreach (EntityField field in ((unit as EntityRelationship).Parent.Parent as EntityFamily).Entities.Find(new Predicate<Entity>(
                                    delegate(Entity e)
                                    {
                                        return e.Name == (unit as EntityRelationship).With.Name;
                                    })).Fields)
                                {
                                    if (field != null && !string.IsNullOrEmpty(field.Name))
                                    {
                                        declarations.Add(new ESharpDeclaration(field.Name, "", "", element.Type));
                                    }
                                }
                                break;
                            case EntityElementType.RelationshipType:
                                declarations.Add(new ESharpDeclaration("parent", "", "", element.Type));
                                declarations.Add(new ESharpDeclaration("child", "", "", element.Type));
                                declarations.Add(new ESharpDeclaration("sibling", "", "", element.Type));
                                break;

                            default:
                                {
                                    System.Diagnostics.Debug.WriteLine("Unknown parse reason: " + reason.ToString());
                                    break;
                                }
                        }

                        break;
                    }
            }

            return declarations.ToArray();
        }

        #region IComparable<ESharpDeclaration> Members
        /// <summary>
        /// Sort alphabetically
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public int CompareTo(ESharpDeclaration other)
        {
            return Title.CompareTo(other.Title);
        }

        #endregion
    }
}
